import java.util.Arrays;

class EmptyException extends RuntimeException {
    public EmptyException() {
        //这是一个提示顺序表为空的异常
    }

    public EmptyException(String massage) {
        super(massage);
    }
}

class PosWrongfulException extends RuntimeException{
    public PosWrongfulException() {
        //PosWrongfulException 一个提示不合法的异常
    }

    public PosWrongfulException(String massage) {
        super(massage);
    }
}

class ArrayList {
    //初始化数组、元素个数
    public int[] elem; // 未初始化的数组
    public int usedSize; // 记录元素个数
    public static final int DEFAULT_SIZE = 10;


    // 构造方法
    public ArrayList() {
        // 初始化数组元素个数为 10 个
        this.elem = new int[DEFAULT_SIZE];
    }

    // 求顺序表的长度
    public int size() {
        // 直接返回元素个数
        return this.usedSize;
    }

    // 判断是不是空间满了的方法
    public Boolean isFull() {
        // 如果顺序表长度大于或者等于数组的长度就是满了
        //if (size() >= this.elem.length) {
            // 此时为满了
            //return true;
        //}
        // 此时为不满
       //return false;

        // 简化的写法
        return size() >= this.elem.length; // 根据返回的真假来判断是否满了
    }

    // 1.在顺序表末尾位置插入一个元素 data
    public void add(int data) {
        // 首先要判断空间是不是满了
        if (isFull()) {
            // 此时满了，要扩容 - 扩容为原来的 2 倍
            this.elem = Arrays.copyOf(this.elem, 2 * this.elem.length);
        }

        // 没满就开始插入操作 usedSize 位置就是末尾的下标
        this.elem[this.usedSize] = data;
        // 元素个数加1
        this.usedSize++;
    }

    // 打印当前顺序表中所有的元素以便于观察结果，这并不是顺序表中的操作!!!
    public void disPlay() {
        for (int i = 0; i < this.usedSize; i++) {
            // 输出的元素之间加上空格
            System.out.print(this.elem[i] + " ");
        }
    }

    // 2.在顺序表指定位置插入一个元素
    public void add(int pos, int data) {
        // 先判断顺序表是不是满的
        if (isFull()) {
            // 满了 - 扩容
            System.out.println("顺序表满了!!!");
            this.elem = Arrays.copyOf(this.elem, 2 * this.elem.length);
        }

        // pos 位置要合法
        if (pos < 0 || pos > this.usedSize) {
            // 此时为不合法
            System.out.println("插入位置不合法!!!");
            throw new PosWrongfulException("位置不合法！！！");
        }

        // 开始插入前要将 pos 位置和他后面的元素向后移
        for (int i = this.usedSize - 1; i >= pos ; i--) {
            // 将前一个元素赋值给后一个
            this.elem[i + 1] = this.elem[i];
        }

        // 开始插入
        this.elem[pos] = data;
        // 元素个数加1
        this.usedSize++;
    }

    //判定是否包含某个元素 - toFind是我要判定的元素
    public boolean contains(int toFind) {
        //size()方法求的是顺序表的长度
        for (int i = 0; i < this.size(); i++) {
            if (this.elem[i] == toFind) {
                return true; //找到了
            }
        }
        return false;///没找到
    }

    //查找某个对应元素的位置 - toFind是我要查找的元素
    public int indexOf (int toFind) {
        //size()方法求的是顺序表的长度
        for (int i = 0; i < this.size(); i++) {
            //若顺序表存储的是引用数据类型，该怎么比较？要使用 equals()来比较
            if (this.elem[i] == toFind) {
                return i; //找到了 - 返回下标
            }
        }
        return -1;//没找到 - 返回-1
    }

    // 判断表是不是空的方法
    public boolean isEmpty() {
        //size()方法求的是顺序表有效元素个数
        return size() == 0;//根据比较的值来返回true或者false
    }

    //获取 pos 元素的位置
    public int get(int pos) {
        if (isEmpty()) {
            //顺序表有可能是空的 - 抛异常来提示
            throw new EmptyException("当前顺序表为空！！！");
        }
        if (pos < 0 || pos >= usedSize) {
            //查找位置的下标可能是负数 - 也可能超过了顺序表的长度 - 抛异常来提示
            throw new PosWrongfulException("get获取元素的时候，pos位置不合法！！！");
        }
        return this.elem[pos]; //此时pos下标就是要找的位置
    }

    // 更新 pos 位置的元素
    public void set(int pos, int value) {
        if (isEmpty()) {
            //顺序表有可能是空的 - 抛异常来提示
            //这里要注意的是此方法是用来更新的，即使是空间满了也不需要扩容
            throw new EmptyException("当前顺序表为空！！！");
        }

        //2.pos位置要合法 - 下标不为负数，不超过数组长度
        if (pos < 0 || pos >= this.usedSize) {
            //查找位置的下标可能是负数 - 也可能超过了顺序表的长度 - 抛异常来提示
            throw new PosWrongfulException("set获取元素的时候，pos位置不合法！！！");
        }

        // 开始更新
        this.elem[pos] = value;  //赋值即可
    }

    // 删除第一次出现的 key 元素
    public void remove(int key) {
        // 顺序表不能是空的
        if (isEmpty()) {
            // 此时顺序表为空
            throw new EmptyException("当前顺序表为空！！！");
        }

        // 调用 indexOf 方法查找 key 的位置
        int index = indexOf(key);

        // 判断此时 key 的下标是不是负数
        if (index == -1) {
            System.out.println("没有这个元素!!!");
            return;
        }

        // 循环遍历覆盖要删除的元素
        for (int i = index; i < this.usedSize - 1; i++) {
            this.elem[i] = this.elem[i + 1];
        }

        // 顺序表元素个数减少一个
        this.usedSize--;
    }

    // 清空顺序表
    public void clear() {
        // 如果是引用类型要置为空
//        for (int i = 0; i < this.usedSize; i++) {
//            this.elem[i] = null;
//        }

        // 普通类型直接将元素个数设为 0 即可
        this.usedSize = 0;
    }
}

public class MyArrayList {

    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();

        //测试在顺序表末尾插入一个元素的方法
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);

        // 测试在顺序表中指定位置插入一个元素
        try{
            arrayList.add(1, 10);//将1下标的位置插入一个10
        }catch (PosWrongfulException e){ //包裹一下可能会抛出的异常
            e.printStackTrace();//如果有异常会提示
        }

        // 测试判定在顺序表中是否包含某个元素的方法
        //System.out.println(arrayList.contains(3)); // 输出 true
        //System.out.println(arrayList.contains(1000)); // 输出 false

        // 测试查找某个对应元素的位置
        //System.out.println(arrayList.indexOf(10)); // 会输出 1

        // 测试 get 方法
        //System.out.println(arrayList.get(3)); // 输出 3

        // 输出更新之前的顺序表元素
        //arrayList.disPlay();
        //System.out.println();
        // 测试 get 方法 - 将 1 下标位置的元素的值改为 100
        //arrayList.set(2, 100);

        // 输出删除之前的顺序表
        arrayList.disPlay();
        System.out.println();

        // 测试删除第一次出现的 key 元素
        arrayList.remove(10);

        // 输出删除之后的顺序表
        arrayList.disPlay();

        // 打印更新之后的顺序表中的元素
        //arrayList.disPlay();
    }
}
